﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BlindData
{
	public static class ValueGenerator
	{
		#region int

		/// <summary>
		/// Returns a random int.
		/// </summary>
		/// <returns></returns>
		public static int Value(this INext<int> next)
		{
			if (next == null)
			{
				throw new ArgumentNullException("next");
			}
			return next.Between(int.MinValue, int.MaxValue);
		}

		public static int Percentage(this INext<int> next)
		{
			if (next == null)
			{
				throw new ArgumentNullException("next");
			}
			return next.Between(0, 100);
		}

		#endregion

		/// <summary>
		/// Returns a random long.
		/// </summary>
		/// <returns></returns>
		public static long Value(this INext<long> next)
		{
			if (next == null)
			{
				throw new ArgumentNullException("next");
			}
			return next.Between(long.MinValue, long.MaxValue);
		}

		#region double

		/// <summary>
		/// Returns a random double.
		/// </summary>
		/// <returns></returns>
		public static double Value(this INext<double> next)
		{
			if (next == null)
			{
				throw new ArgumentNullException("next");
			}
			return next.Between(double.MinValue, double.MaxValue);
		}

		/// <summary>
		/// Returns a random percentage from 0 to 1.
		/// </summary>
		/// <param name="next"></param>
		/// <returns></returns>
		public static double Percentage(this INext<double> next)
		{
			if (next == null)
			{
				throw new ArgumentNullException("next");
			}
			return next.Between(0, 1);
		}

		#endregion

		/// <summary>
		/// Returns a random float.
		/// </summary>
		/// <returns></returns>
		public static float Value(this INext<float> next)
		{
			if (next == null)
			{
				throw new ArgumentNullException("next");
			}
			return next.Between(float.MinValue, float.MaxValue);
		}

		/// <summary>
		/// Returns a random decimal.
		/// </summary>
		/// <returns></returns>
		public static decimal Value(this INext<decimal> next)
		{
			if (next == null)
			{
				throw new ArgumentNullException("next");
			}
			return next.Between(decimal.MinValue, decimal.MaxValue);
		}

		/// <summary>
		/// Returns a random bool.
		/// </summary>
		/// <returns></returns>
		public static bool Value(this INext<bool> next)
		{
			if (next == null)
			{
				throw new ArgumentNullException("next");
			}
			return (next.Generator.Next(2) == 0);
		}

		#region DateTime

		/// <summary>
		/// Returns a random DateTime.
		/// </summary>
		/// <returns></returns>
		public static DateTime Value(this INext<DateTime> next)
		{
			if (next == null)
			{
				throw new ArgumentNullException("next");
			}
			return next.Between(DateTime.MinValue, DateTime.MaxValue);
		}

		#endregion

		#region char

		/// <summary>
		/// Returns a random letter.
		/// </summary>
		/// <returns></returns>
		public static char Letter(this INext<char> next)
		{
			if (next == null)
			{
				throw new ArgumentNullException("next");
			}
			var start = next.Generator.Next<bool>().Value() ? 65 : 97;
			return CreateChar(next, start, 26);
		}

		/// <summary>
		/// Returns a random uppercase letter.
		/// </summary>
		/// <returns></returns>
		public static char UppercaseLetter(this INext<char> next)
		{
			if (next == null)
			{
				throw new ArgumentNullException("next");
			}
			return CreateChar(next, 65, 26);
		}

		/// <summary>
		/// Returns a random lowercase letter.
		/// </summary>
		/// <returns></returns>
		public static char LowercaseLetter(this INext<char> next)
		{
			if (next == null)
			{
				throw new ArgumentNullException("next");
			}
			return CreateChar(next, 97, 26);
		}

		private static char CreateChar(INext<char> next, int start, int range)
		{
			return Convert.ToChar(Convert.ToInt32(Math.Floor(range * next.Generator.NextDouble() + start)));
		}

		#endregion

		/// <summary>
		/// Returns a random string of letter.
		/// </summary>
		/// <param name="length">The length of the string.</param>
		/// <returns></returns>
		public static string Value(this INext<string> next, int length)
		{
			var sb = new StringBuilder();
			for (int i = 0; i < length; i++)
			{
				sb.Append(next.Generator.Next<char>().Letter());
			}
			return sb.ToString();
		}

		#region IList

		/// <summary>
		/// Returns a random index from the list.
		/// </summary>
		/// <param name="list">The list.</param>
		/// <returns></returns>
		public static int Index<T>(this INext<IList<T>> next, IList<T> list)
		{
			if (next == null)
			{
				throw new ArgumentNullException("next");
			}
			return next.Generator.Next<int>().LessThanPositive(list.Count);
		}

		/// <summary>
		/// Returns a random value from the specified list.
		/// </summary>
		/// <param name="list">The list.</param>
		/// <returns></returns>
		public static T Value<T>(this INext<IList<T>> next, IList<T> list)
		{
			if (next == null)
			{
				throw new ArgumentNullException("next");
			}
			return list[next.Index<T>(list)];
		}

		/// <summary>
		/// Returns a random value from the specified list.
		/// </summary>
		/// <param name="list">The list of possible values.</param>
		/// <returns></returns>
		public static T Value<T>(this INext<IList<T>> next, params T[] list)
		{
			if (next == null)
			{
				throw new ArgumentNullException("next");
			}
			return list[next.Index<T>(list)];
		}

		#endregion
	}
}
